// const s = new Set()
// // 最后一个 1 会被忽略掉
// s.add(1).add(2).add(3).add(1)
// console.log(s, s.size, s.has(1))
// console.log(s.delete(3))
// console.log(s)
// s.clear()
// console.log(s)

// const arr = [1, 2, 1, 2, 3, 1, 4]
// const set = new Set(arr)
// console.log(Array.from(set))


// const obj = {}
// obj[true] = true
// obj[321] = 321
// obj[{ name: 1 }] = 'name'
// console.log(Object.keys(obj))

// const map = new Map()
// const user = { name: '小明' }
// map.set(user, 17)
// map.forEach((item, key) => {
//   console.log(item, key)
// })
// console.log(map, map.get({ name: '小明' }), user)
// map.delete(user)
// console.log(map)

// const cache = {}
// // a.js
// cache['001'] = 12
// // b.js
// cache['001'] = 34

// const s = Symbol()
// // 创建的值是独一无二的，永远不会相等
// console.log(s, typeof s, Symbol() === Symbol())
// // 为了方便开发和调试，Symbol 运行我们传入一个字符串作为描述文本
// // 当我们多次使用 Symbol 时就可以通过字符串区分使用了哪个 Symbol
// console.log(Symbol('name'))
// // 从 es2015 开始对象能使用 Symbol 作为属性名（对象属性名可以用 String 和 Symbol）
// const obj = {
//   [Symbol()]:123
// }
// obj[Symbol()] = 123
// obj[Symbol()] = 123
// console.log(obj)

// const name = Symbol('name')
// const user = {
//   [name]: '小明',
//   say () {
//     // 内部可以使用 Symbol 获取成员
//     return this[name]
//   }
// }
// // 外部没法创建一个相同的 Symbol，所以外部不能直接获取成员
// console.log(user[Symbol['name']])
// console.log(user.say())

// const s1 = Symbol('name')
// const s2 = Symbol('name')
// // Symbol.for 提供了一个注册表，为字符串和 Symbol 提供了对应关系
// // 相同字符串，返回相同的值，如果不是字符串，会转换为字符串
// const s3 = Symbol.for('name')
// console.log(s1 === s2, s2 === s3, s3 === s1) // false false false
// console.log(s3, s3 === Symbol.for('name'), Symbol.for(true) === Symbol.for('true')) // Symbol(name) true true

// const obj1 = {
//   name: 'xm',
//   age: 12
// }
// console.log(obj1.toString()) // [object Object]
// // 如果需要重写 toString 方法 我们可以直接
// const obj2 = {
//   name: 'xm',
//   age: 12,
//   toString(){
//     return JSON.stringify(this)
//   }
// }
// // 这种方法可能导致属性名重复
// console.log(obj2.toString()) // {"name":"xm","age":12}
// // es2015 推荐使用 Symbol 实现
// const obj3 = {
//   name: 'xm',
//   age: 12,
//   [Symbol.toStringTag]: 'obj3'
// }
// console.log(obj3.toString()) // [object obj3]

// const user = {
//   [Symbol('name')]:'xm'
// }
// // forin、Object.keys、JSON.stringify 都获取不到 Symbol 属性
// console.log(Object.keys(user),JSON.stringify(user)) //[] {}
// // 获取 Symbol 属性名
// console.log(Object.getOwnPropertySymbols(user))

// const arr = [4, 5, 6, 'xx']
// // 获取到的就是每个元素，而不是下标
// // 相比 forEach 方法，可以使用 break 终止循环
// // forEach 循环终止，需要使用 some/every 替代，some 方法中返回 true ，every 方法返回 false
// for (const item of arr) {
//   console.log(item) // 4 5 6 xx
// }
// // 伪数组也可以遍历，比如 arguments 对象、DOM 操作是的元素节点列表
// const map = new Map()
// map.set('name', 'xm').set('age', 13)
// for (const [key, value] of map) {
//   console.log(key, value) // 'name', 'xm' 'age', 13 
// }


// 遍历对象

// const user = {
//   name: 'xm',
//   age: 12
// }
// for (const item of user) {
//   console.log(item) // TypeError: user is not iterable
// }


// const user = {
//   store:[1,2,3,4],
//   [Symbol.iterator] () {
//     let index = 0
//     const self = this
//     // 迭代器
//     return {
//       next () {
//         return {
//           value: self.store[index++],
//           done: index > self.store.length
//         }
//       }
//     }
//   }
// }
// for(const item of user){
//   console.log(item)
// }

// const todos = {
//   // 生活类任务
//   life: ['逛淘宝', '刷视频', '吃饭'],
//   // 学习类任务
//   learn: ['语文', '数学'],
//   // 工作
//   work: ['写程序']
// }

// // 此时对另一个协作者而言，就必须了解任务列表的结构，才能遍历全部内容
// for (let i = 0; i < todos.life.length; i++) {
//   console.log(todos.life[i])
// }
// for (let i = 0; i < todos.learn.length; i++) {
//   console.log(todos.learn[i])
// }
// for (let i = 0; i < todos.work.length; i++) {
//   console.log(todos.work[i])
// }


// const todos = {
//   // 生活类任务
//   life: ['逛淘宝', '刷视频', '吃饭'],
//   // 学习类任务
//   learn: ['语文', '数学'],
//   // 工作
//   work: ['写程序'],
//   [Symbol.iterator] () {
//     const all = [...this.life, ...this.learn, ...this.work]
//     let index = 0
//     return {
//       next () {
//         return {
//           value: all[index++],
//           done: index > all.length
//         }
//       }
//     }
//   }
// }
// for (const item of todos) {
//   console.log(item)
// }

// // 生成器函数
// function * fun(){
//   console.log('fun')
//   return 100
// }
// const res = fun()
// console.log(res.next())

// function * func(){
//   console.log('func1')
//   yield 100
//   console.log('func2')
//   yield 200
//   console.log('func3')
//   yield 300
// }
// const generator = func()
// console.log(generator.next())
// console.log(generator.next())
// console.log(generator.next())

// id 生成器
// function * createIdMaker(){
//   let id = 1
//   while(true){
//     yield id++
//   }
// }
// const idMakder = createIdMaker()
// console.log(idMakder.next().value)
// console.log(idMakder.next().value)
// console.log(idMakder.next().value)

// 实现对象的 iterator 方法
// const todos = {
//   // 生活类任务
//   life: ['逛淘宝', '刷视频', '吃饭'],
//   // 学习类任务
//   learn: ['语文', '数学'],
//   // 工作
//   work: ['写程序'],
//   [Symbol.iterator]: function * () {
//     const all = [...this.life, ...this.learn, ...this.work]
//     for (let i = 0;i < all.length; i++) {
//       yield all[i]
//     }
//   }
// }
// for (const item of todos) {
//   console.log(item)
// }


// const user = {
//   name: 'xm',
//   age: 12
// }
// console.log(Object.entries(user))
// for (const [key, value] of Object.entries(user)) {
//   console.log(key, value)
// }
// console.log(new Map(Object.entries(user)))


// const user1 = {
//   name: 'xm',
//   age: 12,
//   get info () {
//     return this.name + ':' + this.age
//   }
// }
// // get/set 不能完全复制，复制时只是把 info 单做普通属性复制了
// const user2 = Object.assign({},user1)
// user2.name = 'xh'
// console.log(user2.info) // xm:12

// const descriptions = Object.getOwnPropertyDescriptors(user1)
// const user3 = Object.defineProperties({},descriptions)
// user3.name = 'xh'
// console.log(user3.info) // xh:12

// const user = {
//   name: 2,
//   age: 12,
//   add: 100
// }
// for (const [key, value] of Object.entries(user)) {
//   console.log(key, value)
// }
// for (const [key, value] of Object.entries(user)) {
//   console.log(`${key.padEnd(16, '-')}`, `${value.toString().padStart(3, '0')}`)
// }

 